/*
 * Copyright 2015 Big Switch Networks, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef EBPF_H
#define EBPF_H

#include <stdint.h>

/* eBPF definitions */

struct ebpf_inst {
    uint8_t opcode;
    uint8_t dst : 4;
    uint8_t src : 4;
    int16_t offset;
    int32_t imm;
};

#define EBPF_CLS_MASK 0x07
#define EBPF_ALU_OP_MASK 0xf0

#define EBPF_CLASS(opcode) ((opcode) & 0x07)
#define EBPF_CLS_LD 0x00
#define EBPF_CLS_LDX 0x01
#define EBPF_CLS_ST 0x02
#define EBPF_CLS_STX 0x03
#define EBPF_CLS_ALU 0x04
#define EBPF_CLS_JMP 0x05
#define EBPF_CLS_ALU64 0x07

#define EBPF_SRC(opcode) ((opcode) & 0x08)
#define EBPF_SRC_IMM 0x00
#define EBPF_SRC_REG 0x08

#define EBPF_SIZE(opcode) ((opcode) & 0x18)
#define EBPF_SIZE_W 0x00
#define EBPF_SIZE_H 0x08
#define EBPF_SIZE_B 0x10
#define EBPF_SIZE_DW 0x18

#define EBPF_MODE_IMM 0x00
#define EBPF_MODE_ABS 0x20
#define EBPF_MODE_IND 0x40
#define EBPF_MODE_MEM 0x60
/* 0x80 reserved */
/* 0xa0 reserved */
#define EBPF_MODE_XADD 0xc0

#define EBPF_OP(opcode) ((opcode) & 0xf0)
#define EBPF_ALU_ADD 0x00
#define EBPF_ALU_SUB 0x10
#define EBPF_ALU_MUL 0x20
#define EBPF_ALU_DIV 0x30
#define EBPF_ALU_OR 0x40
#define EBPF_ALU_AND 0x50
#define EBPF_ALU_LSH 0x60
#define EBPF_ALU_RSH 0x70
#define EBPF_ALU_NEG 0x80
#define EBPF_ALU_MOD 0x90
#define EBPF_ALU_XOR 0xa0
#define EBPF_ALU_MOV 0xb0
#define EBPF_ALU_ARSH 0xc0
#define EBPF_ALU_END 0xd0

#define EBPF_JMP_JA 0x00
#define EBPF_JMP_JEQ 0x10
#define EBPF_JMP_JGT 0x20
#define EBPF_JMP_JGE 0x30
#define EBPF_JMP_JSET 0x40
#define EBPF_JMP_JNE 0x50
#define EBPF_JMP_JSGT 0x60
#define EBPF_JMP_JSGE 0x70
#define EBPF_JMP_CALL 0x80
#define EBPF_JMP_EXIT 0x90

#define EBPF_OP_ADD_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_ADD)
#define EBPF_OP_ADD_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_ADD)
#define EBPF_OP_SUB_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_SUB)
#define EBPF_OP_SUB_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_SUB)
#define EBPF_OP_MUL_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_MUL)
#define EBPF_OP_MUL_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_MUL)
#define EBPF_OP_DIV_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_DIV)
#define EBPF_OP_DIV_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_DIV)
#define EBPF_OP_OR_IMM   (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_OR)
#define EBPF_OP_OR_REG   (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_OR)
#define EBPF_OP_AND_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_AND)
#define EBPF_OP_AND_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_AND)
#define EBPF_OP_LSH_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_LSH)
#define EBPF_OP_LSH_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_LSH)
#define EBPF_OP_RSH_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_RSH)
#define EBPF_OP_RSH_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_RSH)
#define EBPF_OP_NEG      (EBPF_CLS_ALU|EBPF_ALU_NEG)
#define EBPF_OP_MOD_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_MOD)
#define EBPF_OP_MOD_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_MOD)
#define EBPF_OP_XOR_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_XOR)
#define EBPF_OP_XOR_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_XOR)
#define EBPF_OP_MOV_IMM  (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_MOV)
#define EBPF_OP_MOV_REG  (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_MOV)
#define EBPF_OP_ARSH_IMM (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_ARSH)
#define EBPF_OP_ARSH_REG (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_ARSH)
#define EBPF_OP_LE       (EBPF_CLS_ALU|EBPF_SRC_IMM|EBPF_ALU_END)
#define EBPF_OP_BE       (EBPF_CLS_ALU|EBPF_SRC_REG|EBPF_ALU_END)

#define EBPF_OP_ADD64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_ADD)
#define EBPF_OP_ADD64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_ADD)
#define EBPF_OP_SUB64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_SUB)
#define EBPF_OP_SUB64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_SUB)
#define EBPF_OP_MUL64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_MUL)
#define EBPF_OP_MUL64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_MUL)
#define EBPF_OP_DIV64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_DIV)
#define EBPF_OP_DIV64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_DIV)
#define EBPF_OP_OR64_IMM   (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_OR)
#define EBPF_OP_OR64_REG   (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_OR)
#define EBPF_OP_AND64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_AND)
#define EBPF_OP_AND64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_AND)
#define EBPF_OP_LSH64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_LSH)
#define EBPF_OP_LSH64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_LSH)
#define EBPF_OP_RSH64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_RSH)
#define EBPF_OP_RSH64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_RSH)
#define EBPF_OP_NEG64      (EBPF_CLS_ALU64|EBPF_ALU_NEG)
#define EBPF_OP_MOD64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_MOD)
#define EBPF_OP_MOD64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_MOD)
#define EBPF_OP_XOR64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_XOR)
#define EBPF_OP_XOR64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_XOR)
#define EBPF_OP_MOV64_IMM  (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_MOV)
#define EBPF_OP_MOV64_REG  (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_MOV)
#define EBPF_OP_ARSH64_IMM (EBPF_CLS_ALU64|EBPF_SRC_IMM|EBPF_ALU_ARSH)
#define EBPF_OP_ARSH64_REG (EBPF_CLS_ALU64|EBPF_SRC_REG|EBPF_ALU_ARSH)

#define EBPF_OP_LDABSB  (EBPF_CLS_LD|EBPF_MODE_ABS|EBPF_SIZE_B)
#define EBPF_OP_LDABSH  (EBPF_CLS_LD|EBPF_MODE_ABS|EBPF_SIZE_H)
#define EBPF_OP_LDABSW  (EBPF_CLS_LD|EBPF_MODE_ABS|EBPF_SIZE_W)
#define EBPF_OP_LDABSDW  (EBPF_CLS_LD|EBPF_MODE_ABS|EBPF_SIZE_DW)
#define EBPF_OP_LDINDB  (EBPF_CLS_LD|EBPF_MODE_IND|EBPF_SIZE_B)
#define EBPF_OP_LDINDH  (EBPF_CLS_LD|EBPF_MODE_IND|EBPF_SIZE_H)
#define EBPF_OP_LDINDW  (EBPF_CLS_LD|EBPF_MODE_IND|EBPF_SIZE_W)
#define EBPF_OP_LDINDDW (EBPF_CLS_LD|EBPF_MODE_IND|EBPF_SIZE_DW)

#define EBPF_OP_LDXW  (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_W)
#define EBPF_OP_LDXH  (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_H)
#define EBPF_OP_LDXB  (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_B)
#define EBPF_OP_LDXDW (EBPF_CLS_LDX|EBPF_MODE_MEM|EBPF_SIZE_DW)
#define EBPF_OP_STW   (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_W)
#define EBPF_OP_STH   (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_H)
#define EBPF_OP_STB   (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_B)
#define EBPF_OP_STDW  (EBPF_CLS_ST|EBPF_MODE_MEM|EBPF_SIZE_DW)
#define EBPF_OP_STXW  (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_W)
#define EBPF_OP_STXH  (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_H)
#define EBPF_OP_STXB  (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_B)
#define EBPF_OP_STXDW (EBPF_CLS_STX|EBPF_MODE_MEM|EBPF_SIZE_DW)
#define EBPF_OP_LDDW  (EBPF_CLS_LD|EBPF_MODE_IMM|EBPF_SIZE_DW)

#define EBPF_OP_JA       (EBPF_CLS_JMP|EBPF_JMP_JA)
#define EBPF_OP_JEQ_IMM  (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_JMP_JEQ)
#define EBPF_OP_JEQ_REG  (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_JMP_JEQ)
#define EBPF_OP_JGT_IMM  (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_JMP_JGT)
#define EBPF_OP_JGT_REG  (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_JMP_JGT)
#define EBPF_OP_JGE_IMM  (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_JMP_JGE)
#define EBPF_OP_JGE_REG  (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_JMP_JGE)
#define EBPF_OP_JSET_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_JMP_JSET)
#define EBPF_OP_JSET_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_JMP_JSET)
#define EBPF_OP_JNE_IMM  (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_JMP_JNE)
#define EBPF_OP_JNE_REG  (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_JMP_JNE)
#define EBPF_OP_JSGT_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_JMP_JSGT)
#define EBPF_OP_JSGT_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_JMP_JSGT)
#define EBPF_OP_JSGE_IMM (EBPF_CLS_JMP|EBPF_SRC_IMM|EBPF_JMP_JSGE)
#define EBPF_OP_JSGE_REG (EBPF_CLS_JMP|EBPF_SRC_REG|EBPF_JMP_JSGE)
#define EBPF_OP_CALL     (EBPF_CLS_JMP|EBPF_JMP_CALL)
#define EBPF_OP_EXIT     (EBPF_CLS_JMP|EBPF_JMP_EXIT)

#endif
